/* Copyright (C) 2008-2009 by Giuseppe Pitta (Darkman) <darkman@darkman.it>
 * 
 * EaZy Psotnic Project
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Net.Sockets;

namespace SocketMan
{

    public class DataEventArgs : EventArgs
    {
        private String data;

        public DataEventArgs(String data)
            : base()
        {
            this.data = data;
        }

        public String DataArrival
        {
            get { return data; }
        }
    }

    public class SocketM
    {
        private TcpClient sock;
        private NetworkStream ns;
        private StreamReader sr;
        private StreamWriter sw;

        private int byteSent;
        private int byteRecv;

        private String hostname;
        private int port;

        public event EventHandler OnConnect;
        public event EventHandler OnDisconnect;
        public event EventHandler<DataEventArgs> OnDataArrival;
        public event EventHandler<ErrorEventArgs> OnError;

        public SocketM()
        {

        }

        public void connect(String hostname, int port, AddressFamily af)
        {
            try
            {
                this.hostname = hostname;
                this.port = port;
                byteSent = 0;
                byteRecv = 0;
                this.sock = new TcpClient(af);
                sock.BeginConnect(hostname, port, new AsyncCallback(connectionCompleted), sock);
            }
            catch (Exception e)
            {
                if (OnError != null)
                    OnError(this, new ErrorEventArgs(e));
            }

        }

        public void connect(String hostname, int port)
        {
            connect(hostname, port, AddressFamily.InterNetwork);
        }

        public void disconnect()
        {
            try
            {
                ns.Close();
                sock.Close();
                if (OnDisconnect != null)
                    OnDisconnect(this, EventArgs.Empty);
            }
            catch (Exception e)
            {
                if (OnError != null)
                    OnError(this, new ErrorEventArgs(e));
            }
        }

        private void connectionCompleted(IAsyncResult ar)
        {
            try
            {
                sock.EndConnect(ar);
                ns = sock.GetStream();
                sr = new StreamReader(ns, Encoding.Default);
                sw = new StreamWriter(ns, Encoding.Default);
                sw.AutoFlush = true;
                if (OnConnect != null)
                    OnConnect(this, EventArgs.Empty);
                read();
            }
            catch (Exception e)
            {
                if (OnError != null)
                    OnError(this, new ErrorEventArgs(e));
            }
        }

        public void sendData(String Data)
        {
            try
            {
                sw.WriteLine(Data);
                byteSent += Data.Length + 1; // non sempre 1char = 1 byte
            }
            catch (Exception e)
            {
                if (OnError != null)
                    OnError(this, new ErrorEventArgs(e));
            }
        }

        private void read()
        {
            String ret;
            try
            {
                while (!sr.EndOfStream)
                {
                    ret = sr.ReadLine();
                    byteRecv += ret.Length + 1;
                    if (OnDataArrival != null)
                        OnDataArrival(this, new DataEventArgs(ret));
                }
                disconnect();
            }
            catch (Exception e)
            {
                if (OnError != null)
                    OnError(this, new ErrorEventArgs(e));
            }
        }

        public int ByteSent
        {
            get { return byteSent; }
        }

        public int ByteRecv
        {
            get { return byteRecv; }
        }

        public int Port
        {
            get { return port; }
        }

        public String Hostname
        {
            get { return hostname; }
        }

        public Boolean isConnected
        {
            get { return (sock != null  && sock.Connected); }
        }

    }
}